Advanced Lane Finding Project

The goals / steps of this project are the following:

  • Compute the camera calibration matrix and distortion coefficients given a set of chessboard images.
  • Apply a distortion correction to raw images.
  • Use color transforms, gradients, etc., to create a thresholded binary image.
  • Apply a perspective transform to rectify binary image ("birds-eye view").
  • Detect lane pixels and fit to find the lane boundary.
  • Determine the curvature of the lane and vehicle position with respect to center.
  • Warp the detected lane boundaries back onto the original image.
  • Output visual display of the lane boundaries and numerical estimation of lane curvature and vehicle position.

Computation of Camera Parameters

Use Chessboard calibration images to get object and imagepoints.

In [1]:
import numpy as np
import cv2
import glob
import matplotlib.pyplot as plt
from lane_line_lib import CameraCalibration

calib = CameraCalibration()

# Arrays to store object points and image points from all the images.
objpoints = [] # 3d points in real world space
imgpoints = [] # 2d points in image plane.

# Make a list of calibration images
images = glob.glob( 'camera_cal/calibration*.jpg')

# Step through the list and search for chessboard corners
for fname in images:
    img = cv2.imread(fname)
    calib.add_calib_image(img)

Compute the calibration and display the distorted and undistorted image

In [9]:
%matplotlib inline

img = cv2.imread('camera_cal/calibration1.jpg')
img_size = (img.shape[1], img.shape[0])

dst = calib.undistort(img)

# Visualize undistortion
f, (ax1, ax2) = plt.subplots(1, 2, figsize=(20, 10))
ax1.imshow(img)
ax1.set_title('Original Image', fontsize=30)
ax2.imshow(dst)
ax2.set_title('Undistorted Image', fontsize=30)
Out[9]:
<matplotlib.text.Text at 0x110615748>

Test Calibration Paramters on straight line images

In [10]:
images = glob.glob( 'test_images/straight_lines*.jpg')

# Step through the list and search for chessboard corners
for fname in images:
    img = cv2.imread( fname )
    img = cv2.cvtColor( img, cv2.COLOR_BGR2RGB )
    dst = calib.undistort(img)
    
    f, (ax1, ax2) = plt.subplots(1, 2, figsize=(20,10))
    ax1.imshow(img)
    ax1.set_title('Original Image', fontsize=30)
    ax2.imshow(dst)
    ax2.set_title('Undistorted Image', fontsize=30)

Biniarize image to lane lines

In [11]:
from lane_line_lib import Binarizer

binarizer = Binarizer()

images = glob.glob( 'test_images/straight_lines*.jpg')

# Step through the list and search for chessboard corners
for fname in images:
    img = cv2.imread( fname )
    dst = calib.undistort(img)
    dst = binarizer.binarize(dst)
    
    img = cv2.cvtColor( img, cv2.COLOR_BGR2RGB )
    f, (ax1, ax2) = plt.subplots(1, 2, figsize=(20,10))
    ax1.imshow(img)
    ax1.set_title('Original Image', fontsize=30)
    ax2.imshow(dst)
    ax2.set_title('Biniarized Image', fontsize=30)

Warp the image to bird view

In [13]:
from lane_line_lib import Warper

src_pts = np.float32([[235, 697],[587,456],[700,456],[1061,690]])

tl = np.float32([src_pts[0, 0], 0])
tr = np.float32([src_pts[3, 0], 0])
dst_pts = np.float32([src_pts[0], tl, tr, src_pts[3]])

warper = Warper( src_pts, dst_pts )

images = glob.glob( 'test_images/straight_lines*.jpg')

for fname in images:
    img = cv2.imread( fname )
    src_img = calib.undistort(img)
    
    cv2.line(src_img, tuple(src_pts[0]), tuple(src_pts[1]), color=[255,0,0], thickness=2)
    cv2.line(src_img, tuple(src_pts[1]), tuple(src_pts[2]), color=[255,0,0], thickness=2)
    cv2.line(src_img, tuple(src_pts[2]), tuple(src_pts[3]), color=[255,0,0], thickness=2)
    cv2.line(src_img, tuple(src_pts[3]), tuple(src_pts[0]), color=[255,0,0], thickness=2)
    
    dst_img = warper.warp( src_img )
    
    src_img = cv2.cvtColor( src_img, cv2.COLOR_BGR2RGB )
    dst_img = cv2.cvtColor( dst_img, cv2.COLOR_BGR2RGB )
    f, (ax1, ax2) = plt.subplots(1, 2, figsize=(20,10))
    ax1.imshow(src_img)
    ax1.set_title('Original Image', fontsize=30)
    ax2.imshow(dst_img)
    ax2.set_title('Warped Image', fontsize=30)

Test the warping on curvature images

In [15]:
images = glob.glob( 'test_images/test*.jpg')

for fname in images:
    img = cv2.imread( fname )
    src_img = calib.undistort(img)
    dst_img = warper.warp( src_img)
    dst_img_bin = binarizer.binarize( dst_img )
    
    src_img = cv2.cvtColor( src_img, cv2.COLOR_BGR2RGB )
    dst_img = cv2.cvtColor( dst_img, cv2.COLOR_BGR2RGB )
    f, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize=(10,5))
    ax1.imshow(src_img)
    ax1.set_title('Original Image', fontsize=12)
    ax2.imshow(dst_img)
    ax2.set_title('Warped Image', fontsize=12)
    ax3.imshow(dst_img_bin)
    ax3.set_title('Binarized Image', fontsize=12)

Histogram of one binarized image

In [16]:
img = cv2.imread( 'test_images/test2.jpg' )

src_img = calib.undistort(img)
dst_img = warper.warp( src_img)
dst_img_bin = binarizer.binarize( dst_img )


histogram = np.sum(dst_img_bin[dst_img_bin.shape[0] // 2:, :, 0], axis=0)
plt.figure(figsize=(8, 3))
plt.plot(histogram)
plt.show()

plt.imshow(dst_img_bin)
plt.show()

Detect Line and display

In [17]:
from lane_line_lib import LaneDetector

detector = LaneDetector()

detector.extract_lane(dst_img_bin)

plt.imshow(detector.out_img)
plt.show()

Create Pipeline and execute

In [18]:
from lane_line_lib import pipeline

img = cv2.imread( 'test_images/test6.jpg' )
img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
plt.imshow( pipeline(img)) 
plt.show()

Execute Pipeline on video

In [ ]:
from moviepy.editor import VideoFileClip

output_file = './processed_project_video.mp4'
input_file = './project_video.mp4'

clip = VideoFileClip(input_file)
out_clip = clip.fl_image(pipeline) 
out_clip.write_videofile(output_file, audio=False)